//****************************************************
// Porman Project 2
// Filename: CWinClass.cpp
// Date: 2009/08/15
// Author: KengYu Lin
// Modify:
//****************************************************
#include "CWinClass.h"

CWinClass::CWinClass( void ) : 
m_hWnd(NULL), 
m_hInstance(NULL),
m_bFullscreen(false), 
m_iW(0), 
m_iH(0),
m_iFPS(0),
m_fFramesPerSecond(0.0f),
m_fLastTime(0.0f)
{
}

bool CWinClass::create( CHAR* Title, int iWidth, int iHeight, int iBits, bool bFullscreen )
{
	WNDCLASS	wc;						// Windows Class Structure
	DWORD		dwExStyle;				// Window Extended Style
	DWORD		dwStyle;				// Window Style

	RECT WindowRect;				    // Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left   = (long)0;		// Set Left Value To 0
	WindowRect.right  = (long)iWidth;	// Set Right Value To Requested Width
	WindowRect.top    = (long)0;		// Set Top Value To 0
	WindowRect.bottom = (long)iHeight;	// Set Bottom Value To Requested Height

	m_bFullscreen = bFullscreen;		// Set The Global Fullscreen Flag

	m_hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc		= (WNDPROC)WndProc;       				// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= m_hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= "GL";							// Set The Class Name

	if( !RegisterClass(&wc) )									// Attempt To Register The Window Class
	{
		MessageBox( NULL, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION );
		return false;											// Return false
	}
	
	if( m_bFullscreen )											// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;								// Device Mode
		memset( &dmScreenSettings, 0, sizeof(DEVMODE) );        // Makes Sure Memory's Cleared
		dmScreenSettings.dmSize = sizeof(DEVMODE);		        // Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth  = iWidth;	                // Selected Screen Width
		dmScreenSettings.dmPelsHeight = iHeight;			    // Selected Screen Height
		dmScreenSettings.dmBitsPerPel = iBits;					// Selected Bits Per Pixel
		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH|DM_PELSHEIGHT;

		if( ChangeDisplaySettings( &dmScreenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
			if( MessageBox( NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "NeHe GL", MB_YESNO|MB_ICONEXCLAMATION) == IDYES )
			{
				m_bFullscreen = false;
			}
			else
			{
				MessageBox( NULL, "Program Will Now Close.", "ERROR", MB_OK|MB_ICONSTOP);
				return false;
			}
		}
	}//End if( m_bFullscreen )

	if( m_bFullscreen )
	{
		dwExStyle = WS_EX_APPWINDOW;							// Window Extended Style
		dwStyle = WS_POPUP;										// Windows Style
		ShowCursor( false );									// Hide Mouse Pointer
	}
	else
	{
		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle = WS_OVERLAPPEDWINDOW;							// Windows Style
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle);		// Adjust Window To true Requested Size

    //----------------------------
	// Create The Window:
    //----------------------------
    m_iW = WindowRect.right-WindowRect.left;
    m_iH = WindowRect.bottom-WindowRect.top;
	if(!( m_hWnd = CreateWindowEx( dwExStyle,						// Extended Style For The Window
						           "GL",						// Class Name
							       Title,							// Window Title
							       dwStyle |						// Defined Window Style
							       WS_CLIPSIBLINGS |				// Required Window Style
							       WS_CLIPCHILDREN,					// Required Window Style
							       0, 0,							// Window Position
							       WindowRect.right-WindowRect.left,// Calculate Window Width
							       WindowRect.bottom-WindowRect.top,// Calculate Window Height
							       NULL,							// No Parent Window
							       NULL,							// No Menu
							       m_hInstance,						// Instance
							       (void*)this)))					// Dont Pass Anything To WM_CREATE
	{
		kill();								
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return false;
	}

    if( initialGL() )
    {
        ShowWindow( m_hWnd, SW_SHOW );					// Show The Window
        SetForegroundWindow( m_hWnd );					// Slightly Higher Priority
        SetFocus( m_hWnd );								// Sets Keyboard Focus To The Window
        return true;									// Success
    }

    return false;
}

int CWinClass::run( void )
{
    MSG msg;
    ::ZeroMemory( &msg, sizeof(MSG) );

    while( msg.message != WM_QUIT )
	{
		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE) )
		{
            TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else										
		{         
            float currentTime = GetTickCount() * 0.001f;    
            ++m_fFramesPerSecond;
            if( currentTime - m_fLastTime > 1.0f )
            {
               m_fLastTime = currentTime;
               m_iFPS = (int)m_fFramesPerSecond;
               m_fFramesPerSecond = 0;
            }

            updateGL();
            swapGL();
            drawGL();
		}
	}//End while(1)

    return (int)msg.wParam;
}

void CWinClass::kill( void )
{
	if( m_bFullscreen )	
	{
		ChangeDisplaySettings(NULL,0);
		ShowCursor(true);
	}

    killGL();
}

LRESULT CALLBACK CWinClass::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch(uMsg)
    {
    case WM_NCCREATE:
        SetWindowLong( hWnd, GWL_USERDATA, (LONG)((LPCREATESTRUCT(lParam))->lpCreateParams) );
        break;
    }

    CWinClass* pWin = (CWinClass*)GetWindowLong( hWnd, GWL_USERDATA );
    if( pWin )
        return pWin->_processWndProce( hWnd, uMsg, wParam, lParam );
    else
        return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

